#pragma warning (disable : 4786)
#pragma comment(lib,"ws2_32.a");
extern "C"
{
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}

#include <string>
#include <iostream>
using namespace std;

//include the luabind headers. Make sure you have the paths set correctly
//to the lua, luabind and Boost files.
#include <luabind/luabind.hpp>
#include <luabind/operator.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/asio.hpp>

using namespace luabind;


boost::asio::io_service g_io;
boost::asio::io_service::work* g_work;

void helper( boost::system::error_code const& err,luabind::object aclosure)
{
	if (!err)
	{
		if (aclosure.is_valid())
		{
			aclosure();
		}
	}
	else
	{
		std::cout<<err.message()<<std::endl;
	}
}
void check()
{
	std::cout<<"checked"<<std::endl;
}
void post(luabind::object aclosure)
{
	//g_io.post( boost::bind( &helper, boost::ref( aclosure ) ) );
	//g_io.post( boost::bind( &helper, aclosure  ) );
	g_io.post( aclosure );
}

class luatimer:boost::noncopyable
{
public:
	luatimer();
	~luatimer(){}

	void start(luabind::object callback, boost::uint32_t ms)
	{
		std::cout<<"timer "<<ms<<std::endl;
		timer_.expires_from_now(boost::posix_time::milliseconds(ms));
		timer_.async_wait(boost::bind(&helper,boost::asio::placeholders::error,callback));
	}

	boost::asio::deadline_timer  timer_;
};

luatimer::luatimer() : timer_(g_io)
{

}
void run()
{
	g_io.run();
}

void stop()
{
	g_io.stop();
}

class gctest
{
public:
	gctest(){}

	void callback(luabind::object o)
	{
		//o_=o;
		o("hi~from c++");
	}

	//luabind::object o_;
};

void register_gctest(lua_State* lua_state)
{

	module(lua_state)
		[
			class_<gctest>("gctest")
			.def(constructor<>())
			.def( "callback", &gctest::callback, dependency(_1,_2) )
			,
			class_<luatimer>("timer")
			.def(constructor<>())
			.def("start",&luatimer::start, dependency(_1,_2))
			,
			def( "post", &post )
			,
			def( "run", &run )
			,
			def( "stop", &stop )
			,
			def("check",&check)
		];

}

struct LuaExceptionGuard
{
	lua_State*  pLua;

	LuaExceptionGuard(lua_State* L):pLua(L){}

	~LuaExceptionGuard()
	{
		lua_close(pLua);
	}
};
inline std::string LuaReportStatus ( lua_State *L, int status = 1 )
{
	std::string msg;
	if ( status && !lua_isnil( L, -1 ) )
	{
		const char* pszMsg = lua_tostring( L, -1 );
		if ( pszMsg == NULL )
		{
			msg = "(error object is not a string)";
		}
		else
		{
			msg = pszMsg;
		}
		lua_pop( L, 1 );
	}
	return msg;
}
inline void RunLuaScript(lua_State* L, const char* script_name)
{
	int error = luaL_dofile(L, script_name);
	if (error != 0)
	{
		//throw std::runtime_error("ERROR(" + ttos(error) + "): Problem with lua script file " + script_name);
		std::cout<<LuaReportStatus(L,error)<<std::endl;
	}
}

int main()
{
	//g_work=new boost::asio::io_service::work(g_io);
	//create a lua state
	lua_State* pLua = lua_open();

	LuaExceptionGuard guard(pLua);

	//open the lua libaries - new in lua5.1
	luaL_openlibs(pLua);

	//open luabind
	open(pLua);

	//bind the relevant classes to Lua
	register_gctest(pLua);


	//load and run the script
	RunLuaScript(pLua, "asiotest.lua");
	//system("pause");
	//delete g_work;

}




















